#include <inc/x86.h>
#include <user/ulib.h>

#include <inc/memlayout.h>
#include <inc/mmu.h>

#include <user/file_server.h>

// this file contains numerous of system api testing

/* void */
/* ux_test(void) */
/* { */
/* 	 int foo = 0; */

/* 	 fork(); */

/* 	 int p = self_idx; */
/* 	 sc_fork(); */
/* 	 wakeup(p); */
	 
/* } */

void
fork_test(void)
{
     fork();
     fork();
     fork();
     fork();

     while (1)
     {
		  kprintf("This is process %d\n", self_idx);
     }
}

void
sfork_test(void)
{
	 sc_sfork();
	 sc_sfork();
	 fork();

	 kprintf("This is process %d\n", self_idx);
	 
	 while (1);
}

void
heap_test(void)
{
     char *test;

     test = malloc(10000);

	 kprintf("malloc = %08x\n", test);

	 uint32_t i;

	 for (i = 0; i != 10000; ++i)
	 {
		  *test = i % 256;
	 }

	 kprintf("freeing\n");
	 free(test);

}

void
sleep_test(void)
{
	 fork();

	 int k = 0;
	 
	 switch (self_idx)
	 {
	 case 0:

		  while (1)
		  {
			   int i;
			   
			   for (i = 0; i != 100000000; ++i)
					;
			   			   
			   if (wakeup(1, NULL) == 0)
					kprintf("[Make a joke!]%d\n", k ++);
			   else kprintf("ooops ...\n");
		  }
		  
		  break;
		  
	 case 1:

		  while (1)
		  {
			   kprintf("Hmm ... %d\nNow I'm going to sleep!\n", k ++);
			   sleep(self_idx, NULL);
		  }
		  
		  break;
	 }
}

void
iec_test(void)
{
	 fork();

	 if (self_idx != 0)
	 {
		  fork();
		  fork();
		  fork();
	 }
	 

	 int self;
	 struct env_t *env;
	 int i;
	 
	 if (self_idx > 0)
	 {
		  i = 0;
		  
		  while (1)
		  {
			   int err;
			   kprintf("%d: Hmm, I'm going to send! - %d\n", self_idx,
					   err = iec_send(0, i ++, 0, 0, 0));

			   if (err == 0) waitb(ENV_SCH_IEC_SEND_BLOCKING);
		  }

	 }
	 else
	 {

		  self = self_idx;
		  env = envs + self;

		  while (1)
		  {
			   int x; for (x = 0; x != 2000000; ++x) ;
			   
			   waitb(ENV_SCH_IEC_RECV_BLOCKING);

			   kprintf("Got the message, pidx = %d, i = %d\n",
			   		   env->iec.recv.begin,
			   		   envs[env->iec.recv.begin].iec.cache.arg_a);

			   iec_recv(env->iec.recv.begin);
		  }
	 }
}

void
pipe_test()
{
	 fork();

	 struct pipe_t *pipe;
	 uint32_t h;
	 if (self_idx == 0)
	 {
	 	  struct env_t *env = envs + self_idx;

	 	  pipe = pipe_new();
	 	  h = pipe_share(pipe);

	 	  waitb(ENV_SCH_IEC_RECV_BLOCKING);
	 	  uint32_t c = env->iec.recv.begin;

	 	  kprintf("send handler to c, %d\n", h);
		  
	 	  iec_send(c, h, 0, 0, 0);
	 	  waitb(ENV_SCH_IEC_SEND_BLOCKING);

	 	  int i;
		  i = 0;
	 	  while (1)
	 	  {
			   int x; for (x = 0; x != 2000000; ++x) ;

			   i ++;
			   kprintf("send %d\n", i);
	 		   pipe_block_write(pipe, (char *)&i, 4);
	 	  }
	 }
	 else
	 {
	 	  struct env_t *env = envs + self_idx;
		  
	 	  iec_send(0, 0, 0, 0, 0);
	 	  waitb(ENV_SCH_IEC_RECV_BLOCKING);

	 	  h = envs[env->iec.recv.begin].iec.cache.arg_a;
	 	  iec_recv(0);

	 	  kprintf("recv handler, %d\n", h);

	 	  pipe = pipe_open(h);

	 	  int i;
	 	  while (1)
	 	  {
	 		   pipe_block_read(pipe, (char *)&i, 4);
	 		   kprintf("recv : %d\n", i);
	 	  }
	 }
}

void
rpc_test(void)
{
	 fork();

	 if (self_idx == 0)
	 {
		  uint16_t idx;
		  uint32_t func;
		  struct pipe_t *in_pipe, *out_pipe;


		  while (1)
		  {
			   kprintf("wait for rpc request\n");
			   rpc_recv(&idx, &func, &in_pipe, &out_pipe);
			   kprintf("recv rpc request\n");
			   
			   int a, b;
		  
			   pipe_block_read(in_pipe, (char *)&a, sizeof(a));
			   pipe_block_read(in_pipe, (char *)&b, sizeof(b));

			   int c = a + b;
			   pipe_block_write(out_pipe, (char *)&c, sizeof(c));
		  
			   rpc_return(idx, in_pipe, out_pipe);
		  }
	 }
	 else
	 {
		  int a = 0, b = 0, c;
		  while (1)
		  {
			   a = (a + b) % 256;
			   b = (b + 1) % 256;

			   kprintf("send rpc request\n");
			   rpc_send(0, 0);

			   pipe_block_write(rpc_in_pipe, (char *)&a, sizeof(a));
			   pipe_block_write(rpc_in_pipe, (char *)&b, sizeof(b));
			   
			   rpc_wait();

			   pipe_block_read(rpc_out_pipe, (char *)&c, sizeof(c));

			   kprintf("%d + %d = %d\n", a, b, c);
		  }
	 }
	 
}

void
lfs_test(void)
{
	 init_ramfs_driver();
	 init_fs();

	 extern char fs_init_image[];
	 struct fs_node_t *root = open_root();
	 
	 fs_seek(root, FS_SEEK_FIND, 0);
	 fs_write(root, "test.txt", 8);
	 struct fs_node_t *test = fs_open(root);
		 
	 char *buf[256];
	 int n = fs_read(test, buf, 256);
	 buf[n] = '\0';
	 
	 kprintf("data : %s\n", buf);
	 
	 fs_close(test);
	 
	 while (1) ;
}

void
fs_test(void)
{
	 struct file_t *root = file_open_root();
	 file_write(root, "test.txt", 8);
	 struct file_t *file = file_open(root);

	 char *buf[256];
	 file_seek(file, FS_SEEK_BEGIN, 4);
	 int n = file_read(file, buf, 256);
	 buf[n] = '\0';
	 
	 kprintf("data from test.txt : %s\n", buf);

	 kprintf("finished\n");
	 while (1);
}

void
spawn_test(void)
{
	 char *a = malloc(10);
	 
	 spawn("hello");

	 kprintf("finished\n");
	 while (1);
}

void
test_main(void)
{
	 spawn_test();
}
